/*
 * Copyright 2012 Finbudget.com
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package finbudgettable.client.ui.grid.style;

import java.util.*;

/**
 * Creates and removes css rules dynamically. Can store rules definitions for a while and restore them on demand.
 */
public class CssController {

    /**
     * This class is used to store style's properties between "sessions"
     */
    static class StoredRule {

        /**
         * A rule's selectorText
         */
        private final String selectorText;

        /**
         * Rules's styles
         */
        private final Map<String, String> styles = new HashMap<String, String>();

        StoredRule(String selectorText) {
            this.selectorText = selectorText;
        }

        public void setStyle(String name, String value) {
            styles.put(name, value);
        }

        public String getSelectorText() {
            return selectorText;
        }

        public Set<Map.Entry<String, String>> getStyles() {
            return styles.entrySet();
        }
    }

    /**
     * This list keeps rules definitions between calling restoreRules() and restoreRules()
     */
    private final List<StoredRule> storedRules = new ArrayList<StoredRule>();

    /**
     * Keeps a list of managed css rules
     */
    private final List<Rule> currentRules = new ArrayList<Rule>();

    /**
     * The convenient method to get unique css class name
     *
     * @return a unique class name
     */
    public String getNextClassName() {
        return CssUtils.getNextClassName();
    }

    /**
     * Creates css rule dynamycally and makes it manageable
     *
     * @param ruleName rule name
     * @return JavaScript rule object
     */
    public Rule createRule(String ruleName) {
        StyleSheets sheets = StyleSheets.get();
        if (sheets.getLength() > 0) {
            Rule rule = CssUtils.getRule(ruleName);
            if (rule != null) {
                return rule;
            }
            sheets.get(0).addRule(ruleName);
            rule = CssUtils.getRule(ruleName);
            if (rule != null) {
                currentRules.add(rule);
            }
            return rule;
        }
        return null;
    }

    /**
     * Removes managed rules from a browser
     */
    public void clear() {
        for (Rule rule : currentRules) {
            CssUtils.removeRule(rule.getSelectorText());
        }
        currentRules.clear();
    }

    /**
     * Creates stored rules in a browser
     */
    public void restoreRules() {
        for (StoredRule rule : storedRules) {
            Rule newRule = createRule(rule.getSelectorText());
            for (Map.Entry<String, String> style : rule.getStyles())
                newRule.getStyle().setProperty(style.getKey(), style.getValue());
        }
    }

    /**
     * Saves managed rules definitions
     */
    public void storeRestore() {
        storedRules.clear();
        for (Rule rule : currentRules) {
            StoredRule storedRule = new StoredRule(rule.getSelectorText());
            for (int propIndex = 0; propIndex < rule.getStyle().getLength(); propIndex++) {
                String name = getPropertyNameAsCamelCase(rule.getStyle().getPropertyName(propIndex));
                String value = rule.getStyle().getProperty(name);
                storedRule.setStyle(name, value);
            }
            storedRules.add(storedRule);
        }
    }

    private static String getPropertyNameAsCamelCase(String name) {
        StringBuilder sb = new StringBuilder();
        sb.append(name.charAt(0));
        for (int i = 1; i < name.length(); i++) {
            char symbol = name.charAt(i);
            if (symbol == '-') {
                continue;
            }
            if (name.charAt(i - 1) == '-') {
                symbol = Character.toUpperCase(symbol);
            }
            sb.append(symbol);
        }
        return sb.toString();
    }
}
